/***********************************************************
 *   > File Name: IIC.c
 *   > Author: fly
 *   > Create Time: 2021-07-22  4/29  18:51:57 +0800
 *========================================================*/
#include <IIC.h>
#include <include.h>

typedef struct{
    unsigned int GPD0CON;
    unsigned int GPD0DAT;
    unsigned int GPD0PUD;
    unsigned int GPD0DRV;
    unsigned int GPD0CONPDN;
    unsigned int GPD0PUDPDN;
}gpd0;
#define GPD0    (*(volatile gpd0*)0xE02000A0)

typedef struct{
    unsigned int GPD1CON;
    unsigned int GPD1DAT;
    unsigned int GPD1PUD;
    unsigned int GPD1DRV;
    unsigned int GPD1CONPDN;
    unsigned int GPD1PUDPDN;   
}gpd1;
#define GPD1    (*(volatile gpd1*)0xE02000C0)

typedef struct{
    unsigned int I2CCON;
    unsigned int I2CSTAT;
    unsigned int I2CADD;
    unsigned int I2CDS;
    unsigned int I2CLC;
}i2c0;
#define I2C0    (*(volatile i2c0*)0xE1800000)

void mydelay_ms(int time)  
{  
    int i, j;  
    while(time--)  
    {  
        for (i = 0; i < 5; i++)  
            for (j = 0; j < 514; j++);  
    }  
}  
/**********************************************************************  
 * @brief       iic read a byte program body  
 * @param[in]   slave_addr, addr, &data  
 * @return      None  
 **********************************************************************/  
void iic_read(unsigned char slave_addr, unsigned char addr, unsigned char *data)  
{  
    printf("[%s] slave_addr: 0x%X, addr: 0x%X\n", __func__, slave_addr, addr);
    I2C0.I2CDS = slave_addr; //将从机地址写入I2CDS寄存器中  
    I2C0.I2CCON = (1 << 7)|(1 << 6)|(1 << 5); //设置时钟并使能中断  
    I2C0.I2CSTAT = 0xf0; //[7:6]设置为0b11，主机发送模式；  
                         //往[5：4]位写0b11，即产生启动信号,发出IICDS寄存器中的地址  
    __DBG_PRINT__;
    while(!(I2C0.I2CCON & (1 << 4))); // 等待传输结束，传输结束后，I2CCON [4]位为1，标识有中断发生；  
                                      // 此位为1时，SCL线被拉低，此时I2C传输停止；  
    I2C0.I2CDS = addr; //写命令值  
    I2C0.I2CCON = I2C0.I2CCON & (~(1 << 4)); // I2CCON [4]位清0，继续传输  
    __DBG_PRINT__;
    while(!(I2C0.I2CCON & (1 << 4))); // 等待传输结束  
    I2C0.I2CSTAT = 0xD0; // I2CSTAT[5:4]位写0b01,发出停止信号  
  
    I2C0.I2CDS = slave_addr | 1; //表示要读出数据  
    I2C0.I2CCON = (1 << 7)|(1 << 6) |(1 << 5) ; //设置时钟并使能中断  
    I2C0.I2CSTAT = 0xb0; //[7:6]位0b10,主机接收模式；  
                         //往[5：4]位写0b11，即产生启动信号,发出IICDS寄存器中的地址  
    //I2C0.I2CCON = I2C0.I2CCON & (~(1 << 4));  
    __DBG_PRINT__;
    while(!(I2C0.I2CCON & (1 << 4))); //等待传输结束，接收数据  
  
    I2C0.I2CCON &= ~((1<<7)|(1 << 4)); // I2CCON [4]位清0，继续传输，接收数据，  
                                       // 主机接收器接收到最后一字节数据后，不发出应答信号 no ack  
                                       // 从机发送器释放SDA线，以允许主机发出P信号，停止传输； 
    __DBG_PRINT__; 
    while(!(I2C0.I2CCON & (1 << 4)));  // 等待传输结束 
    *data = I2C0.I2CDS;
    I2C0.I2CSTAT = 0x90;
    I2C0.I2CCON &= ~(1<<4);     /*clean interrupt pending bit  */
    __DBG_PRINT__;
    printf("[%s]data: 0x%X\n", __func__, *data);
}
/**********************************************************************
 * @brief       iic write a byte program body
 * @param[in]   slave_addr, addr, data
 * @return      None
 **********************************************************************/
void iic_write (unsigned char slave_addr, unsigned char addr, unsigned char data)
{
    printf("[%s] slave_addr: 0x%X, addr: 0x%X, data: 0x%X\n", __func__, slave_addr, addr, data);
    I2C0.I2CDS = slave_addr;
    I2C0.I2CCON = (1 << 7)|(1 << 6)|(1 << 5) ;
    I2C0.I2CSTAT = 0xf0;
    __DBG_PRINT__;
    while(!(I2C0.I2CCON & (1 << 4)));
 
    I2C0.I2CDS = addr;
    I2C0.I2CCON = I2C0.I2CCON & (~(1 << 4));
    __DBG_PRINT__;
    while(!(I2C0.I2CCON & (1 << 4)));
 
    I2C0.I2CDS = data;
    I2C0.I2CCON = I2C0.I2CCON & (~(1 << 4));
    __DBG_PRINT__;
    while(!(I2C0.I2CCON & (1 << 4)));
 
    I2C0.I2CSTAT = 0xd0;
    I2C0.I2CCON = I2C0.I2CCON & (~(1 << 4));
    mydelay_ms(10);
    __DBG_PRINT__;
}

static void KXTF9_2050_PowerOn(void)
{
    __DBG_PRINT__;
    GPD0.GPD0CON &= ~(0xf<<12); // clear bit[15:12] 
    GPD0.GPD0CON |= (0x1<<12); // set output mode
    GPD0.GPD0DAT |= (0x1<<3);   // set hight

    mydelay_ms(20); 
}

void KXTF9_2050_Init(void)
{
    GPD1.GPD1CON &= ~(0xFF<<0); // clear bit[7:0]
    GPD1.GPD1CON |= (0x22<<0);  // Config I2C0 pin
    KXTF9_2050_PowerOn();
    __DBG_PRINT__;

    unsigned char client = 0x1e;
    unsigned char val;
    int cnt = 20;

    /* sleep */
    iic_read(client, 0x1b, &val);
    val = val & 0x7f;
    iic_write(client, 0x1b, val);

    /* reset */
    iic_read(client, 0x1d, &val);
    val = val | 0x80;
    iic_write(client, 0x1d, val);

    /* wait for software reset */
    do{
        mydelay_ms(10);
        iic_read(client, 0x1d, &val);
        __DBG_PRINT__;
    } while( ((val & 0x80) == 0x80) && (--cnt > 0) );

    /* initial regs */
    iic_write(client, 0x1b, 0x00);
    iic_write(client, 0x1e, 0x38);
    iic_write(client, 0x21, 0x04);
    iic_write(client, 0x1b, 0x60);
    iic_write(client, 0x1b, 0xe0);

    /* read chip id */
    iic_read(client, 0x0f, &val);
    printf("gsensor's ID: 0x%02x\n", val);
}

void test_gsensor(void)
{
    uart0_init();
    uart2_init();
    KXTF9_2050_Init();

    for(;;){
        printf("=======================\n");
        mydelay_ms(900000);
    }
}